package com.etone.smartAudit.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.etone.eos.domain.CreateParam;
import com.etone.eos.domain.CreateParamDTO;
import com.etone.eos.domain.CreateParamVO;
import com.etone.eos.domain.MD5FileVO;
import com.etone.smartAudit.domain.*;
import com.etone.smartAudit.error.CustomParameterizedException;
import com.etone.smartAudit.mapper.AdminMapper;
import com.etone.smartAudit.mapper.CertificateUploadFileMapper;
import com.etone.smartAudit.security.SecurityUtils;
import com.etone.smartAudit.vo.FileVO;
import com.etone.smartAudit.vo.bns.SetChainDTO;
import com.etone.smartAudit.vo.bns.SetChainVO;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

@Service
public class CertificateUploadFileService extends ServiceImpl<CertificateUploadFileMapper, CertificateUploadFile> {


    @Autowired
    private BSNService bsnService;

    @Value("${audit.filePath}")
    private String filePath;


    @Autowired
    private ThreadPoolTaskExecutor executor;

    @Autowired
    private CertificateFileService cerService;

    @Autowired
    private CertificatePersonService personService;

    @Autowired
    private ProjectFileService projectFileService;

    @Autowired
    private AdminMapper adminMapper;

    @Autowired
    private CertificateGroupService groupService;

    @Autowired
    private EosService eosService;

    /***
     * 保存文件
     * @param fileVOS 文件列表
     * @param id  相关联id
     * @param type 类型
     */
    @Transactional
    public void saveFile(List<FileVO> fileVOS, Integer id, Integer type) {

        if (CollectionUtil.isEmpty(fileVOS)) {
            return;
        }
        //0-执行人附件，1-存证单附件
        CertificatePerson person = null;
        String oldFileIds = null;
        if (type == 0) {
            //获取执行人
            person = personService.getById(id);
            if (person == null) {
                throw new CustomParameterizedException("执行人已经不存在");
            }
            id = person.getCerFileid();

        } else if (type == 1) {
            //存证单附件不在这里添加

        } else {
            throw new CustomParameterizedException("错误的文件类型");
        }
        //根据项目id 创建需求单或者确认单文件夹
        CertificateFile certificateFile = cerService.getById(id);
        if (certificateFile == null) {
            throw new CustomParameterizedException("该单已经不存在");
        }
        //存证单类型
        Integer cerType = certificateFile.getType();

        //项目id
        Integer projectId = certificateFile.getItemId();

        String loginAdminName = SecurityUtils.getCurrentUserLogin();
        Admin admin = adminMapper.findByAccount(loginAdminName);
        if (admin == null) {
            //默认获取当前管理员
            admin = adminMapper.findByAccount("admin");

        }
        if (admin != null) {
            admin.setHasCreateFile(true);
        }

        //项目->需求单/确认单->群组->单->文件
//        certificateFile.getGroupId()
        //获取需求单或者确认单文件
        ProjectFile cerProject = projectFileService.getCerDir(projectId, cerType, admin);

        //获取群组文件
        CertificateGroup group = groupService.getById(certificateFile.getGroupId());
        if (group == null) {
            throw new CustomParameterizedException("群组不存在");
        }
        ProjectFile groupProject = projectFileService.getCerDir(projectId, group.getGroupName(), admin, cerProject.getId());

        //获取单文件夹
        ProjectFile parentProject = projectFileService.getCerDir(projectId, certificateFile.getName(), admin, groupProject.getId());

//        ProjectFile parentProject = projectFileService.getCerDir(projectId, cerType, admin);


        //处理文件同步
        if (type == 0) {
            oldFileIds = person.getFileIds();
        } else {
            oldFileIds = certificateFile.getFileIds();
        }
        //添加差异的文件
        String fileIds = getFileIds(oldFileIds, fileVOS, admin, parentProject, projectId);

        if (type == 0) {
            person.setFileIds(fileIds);
            personService.updateById(person);
        } else if (type == 1) {
            certificateFile.setFileIds(fileIds);
            cerService.updateById(certificateFile);
        }

    }

    /***
     * 处理文件同步,获取附件文件id
     * @param oldFileIds
     * @param fileVOS
     */
    private String getFileIds(String oldFileIds, List<FileVO> fileVOS, Admin admin, ProjectFile parentProject, Integer projectId) {
        List<FileVO> addFiles = new ArrayList<>();
        List<String> newFileds = new ArrayList<>();
        if (fileVOS == null) {
            return "";
        }
        fileVOS.stream().forEach(fileVO -> {
            if (StrUtil.isNotEmpty(fileVO.getId())) {
                newFileds.add(fileVO.getId());
            } else {
                //如果主键id为空则是新添加的
                addFiles.add(fileVO);
            }
        });
        List<Integer> removeIds = new ArrayList<>();

        List<String> oldList = new ArrayList<>();
        if (StrUtil.isNotEmpty(oldFileIds)) {
            String[] oldIdList = oldFileIds.split(",");
            oldList = Arrays.asList(oldIdList);
        }
        //删除去掉的文件  原文件中有的，新文件中不存在的
        oldList.stream().forEach(oldId -> {
            if (!newFileds.contains(oldId)) {
                if (StrUtil.isNotEmpty(oldId)) {
                    try {
                        removeIds.add(Integer.valueOf(oldId));
                    } catch (Exception e) {
                        log.error("处理移除旧文件失败", e);
                    }
                }
            }
        });
        //添加新文件，原文件中没有的，新文件中有的

        //执行删除
        if (CollectionUtil.isNotEmpty(removeIds)) {
            projectFileService.removeByIds(removeIds);
        }
        //执行添加
        if (CollectionUtil.isNotEmpty(addFiles)) {
            addFiles.stream().forEach(fileVO -> {
                String name = fileVO.getOriginName();
                if (StrUtil.isNotEmpty(name)) {
                    String sortName = name.substring(0, name.lastIndexOf("."));
                    String extName = name.substring(name.lastIndexOf("."));
//                    name = sortName + "_" + System.currentTimeMillis() + extName;
                    name = sortName + "_" + DateUtil.format(new Date(), "yyyyMMddHHmmssSSS") + extName;
                    fileVO.setOriginName(name);
                }
            });
        }
        //添加文件
        List<ProjectFile> list = projectFileService.saveRealFile(admin, addFiles, parentProject.getId(), projectId);
        list.stream().forEach(file -> newFileds.add(file.getId() + ""));

        //异步执行区块上链
        handDnsHash(list);

        StringJoiner fileIds = new StringJoiner(",");
        newFileds.stream().forEach(id -> fileIds.add(id));

        return fileIds.toString();
    }

    /***
     * hand  dns  hash
     * @param list
     */
    private void handDnsHash(List<ProjectFile> list) {
        try {
            list.stream().forEach(vo -> {
                executor.execute(() -> {
                    vo.setHash(getHash(vo));
                    projectFileService.updateById(vo);
                    ThreadUtil.sleep(800);
                });
            });
        } catch (Exception e) {
            log.error("dns has fail");
        }
    }


    private String getHash(ProjectFile projectFile) {
        try {
            SetChainDTO dto = new SetChainDTO();
            dto.setHash(projectFile.getHash());
            dto.setUid(projectFile.getFileMd5());
            dto.setContent("存证区块上链");
//            SetChainVO vo = bsnService.fileSetChain(dto);
//            return vo.getHash();
            CreateParamDTO createParamDTO = new CreateParamDTO();
            createParamDTO.setFileName(projectFile.getFileName());
            createParamDTO.setMac(projectFile.getHash());
            createParamDTO.setMd5(projectFile.getFileMd5());
            createParamDTO.setAppId("smart");
            createParamDTO.setUserId("smart");
            MD5FileVO param = eosService.addFile(createParamDTO);
//            return String.valueOf(param.getMd5());
            return param.getHash();
        } catch (Exception e) {
            log.error("上链失败", e);
        }
        return null;
    }

    public static void main(String[] args) {
        System.out.println(DateUtil.format(new Date(), "yyyyMMddHHmmssSSS"));
    }
}
